package loes0;

/**
 * Main Simulator class for the discrete event simulation
 * 
 * @author David Stezenbach
 * @author Michael Hoefling
 * 
 */
public class Simulator {
	private long simTimeInRealTime;
	private long now;
	private SortableQueue ec;
	private SortableQueue cq;
	private boolean stop;
	public Stichproben stichproben;
	private DiscreteTimeCounter dtc;

	public Simulator() {
		stichproben = new Stichproben();
		ec = new SortableQueue();
		cq = new SortableQueue();
		
	}
	
	public void report(){
		dtc = new DiscreteTimeCounter(stichproben);
		dtc.report();
	}

	/**
	 * Sets the number of units in sim time representing one unit in real time
	 * 
	 * @param simTimeInRealTime
	 *            number of ticks per unit in real time
	 */
	public void setSimTimeInRealTime(long simTimeInRealTime) {
		this.simTimeInRealTime = simTimeInRealTime;
	}

	/**
	 * Converts real time to sim time
	 * 
	 * @param realTime
	 *            units in real time
	 * @return units in sim time
	 * @throws Exception
	 *             if simtime is out of range
	 */
	public long realTimeToSimTime(double realTime) throws NumberFormatException {
		double tmp = realTime * simTimeInRealTime;
		if (tmp > Long.MAX_VALUE)
			throw new NumberFormatException("simulation time out of range: "
					+ tmp + " > " + Long.MAX_VALUE);
		return (long) Math.ceil(tmp);
	}

	/**
	 * Converts sim time to real time
	 * 
	 * @param simTime
	 *            units in sim time
	 * @return units in real time
	 */
	public double simTimeToRealTime(long simTime) {
		return (double) simTime / simTimeInRealTime;
	}

	/**
	 * Starts the simulation
	 * 
	 * @throws Exception
	 *             is thrown when event order is invalid
	 */
	public void run() {
		while (!stop) {
			Event e = (Event) ec.popNextElement();
			if (e != null) {
				/*
				 * check if event time is in the past
				 */
				if (e.getTime() < now)
					throw new RuntimeException("Event time " + e.getTime()
							+ " smaller than current time " + now);
				/*
				 * set event time as new simtime
				 */
				now = e.getTime();
				/*
				 * process event
				 */
				e.process();
			} else {
				System.out.println("Event chain empty.");
				stop = true;
			}
		}
	}

	/**
	 * Pushes a new event into the event chain at the correct place
	 * 
	 * @param e
	 *            the new event
	 */
	public void pushNewEvent(Event e) {
		ec.pushNewElement(e);
	}

	/**
	 * Pushes a new customer into the customerQ at the correct place
	 * 
	 * @param c
	 *            the new customer
	 */
	public void pushNewCustomer(Customer c) {
		this.cq.pushNewElement(c);
		
	}

	/**
	 * Stops the simulator
	 */
	public void stop() {
		stop = true;
	}

	public void start() {
		stop = false;
	}

	/**
	 * Returns the current sim time
	 * 
	 * @return current sim time
	 */
	public long getSimTime() {
		return now;
	}

	/**
	 * Resets the simulator
	 */
	public void reset() {
		now = 0;
		stop = false;
		ec.clear();
	}

	public void setServiceCompletionTime(long simTime) {
		Customer c = (Customer) cq.popNextElement();
		c.setServiceCompletion(simTime);
		cq.pushNewElement(c);
//		System.out.println("Kundenabarbeitung Fertig");
		System.out.println(c);
		

	}

	public void setServiceInitTime(long simTime) {
		Customer c = (Customer) cq.popNextElement();
		c.setServiceInitiation(simTime);
		cq.pushNewElement(c);
//		System.out.println("Kundenabarbeitung Initialisiert");
		

	}

	public void popCustomer() {
		Customer c = (Customer) this.cq.popNextElement();
		stichproben.pushCustomer(c);
	}
}
